/*
 * Interface.cpp
 *
 *  Created on: 10/06/2010
 *      Author: marce
 */

#include "Interface.h"
#include "Compresor.h"
#include "Manejadores/ManejadorArbol.h"
#include "Manejadores/ManejadorHash.h"

#include <iostream>
#include <map>

#define ERROR_ORDEN					1
#define ERROR_ARCHIVO				2
#define ERROR_PARAMETRO_INEXISTENTE	3
#define ERROR_FALTA_CONTEXTO		4
#define ERROR_MULTIPLES_OPERACIONES	5

using namespace std;

bool esSi() {
	char elegida;

	fflush(stdout);
	elegida = fgetc(stdin);

	if (elegida=='S' || elegida=='s') {
		return true;
	} else {
		return false;
	}
}

bool esArchivoComprimido(char * nombreArchivo) {
	char extension[]="klow";

	char * comienzoExtension;

	comienzoExtension = strrchr(nombreArchivo,'.');

	if (comienzoExtension != NULL) {
		if (strcmp(extension,comienzoExtension + sizeof(char))==0) {
			return true;
		}
	}


	return false;
}

char * obtenerArchivoComprimido(char * nombreOriginal) {
	char extension[]=".klow";
	char * nuevoNombre;
	unsigned short int longitud = strlen(nombreOriginal) + strlen(extension) + 1;

	nuevoNombre = new char [longitud];
	memset(nuevoNombre,0,longitud);

	strcat(nuevoNombre,nombreOriginal);
	strcat(nuevoNombre,extension);

	return nuevoNombre;
}

bool aceptaDescomprimirDistintaExtencion() {
	printf ("Esta intentando descomprimir un archivo que no tiene la extension relacionada al programa (.klow). ¿Desea descomprimir el archivo igualmente? [S/N]\n");
	return esSi();
}

bool aceptaEstadisticasDistintaExtencion() {
	printf ("Esta intentando ver estadisticas de un archivo que no tiene la extension relacionada al programa (.klow). ¿Desea descomprimir el archivo igualmente? [S/N]\n");
	return esSi();
}

void mostrarError(unsigned int codigoError) {
	switch(codigoError){
		case ERROR_ORDEN:
			printf ("\nERROR: Orden del compresor no especificado o invalido. Debe ingresar un numero entre 0 y 100.\n");
			break;
		case ERROR_ARCHIVO:
			printf ("\nERROR: Archivo de trabajo no especificado.\n");
			break;
		case ERROR_PARAMETRO_INEXISTENTE:
			printf ("\nERROR: Parametro inexistente.\n");
			break;
		case ERROR_FALTA_CONTEXTO:
			printf ("\nERROR: No ingreso el contexto que desea ver.\n");
			break;
		case ERROR_MULTIPLES_OPERACIONES:
			printf ("\nERROR: Solo se permite una operacion principal por vez (compresion o descompresion).\n");
			break;
	}
	printf ("Utilice el comando -h para visualiza la ayuda.\n");
}

bool esOpcion(char * opcion) {
	if (strcmp(opcion,"-c") == 0 || strcmp(opcion,"-C") == 0 ||
		strcmp(opcion,"-d") == 0 || strcmp(opcion,"-D") == 0 ||
		strcmp(opcion,"-e") == 0 || strcmp(opcion,"-E") == 0 ||
		strcmp(opcion,"-f") == 0 || strcmp(opcion,"-F") == 0 ||
		strcmp(opcion,"-v") == 0 || strcmp(opcion,"-V") == 0 ||
		strcmp(opcion,"-vv") == 0 || strcmp(opcion,"-VV") == 0 ||
		strcmp(opcion,"-h") == 0 || strcmp(opcion,"-H") == 0) {
		return true;
	} else {
		return false;
	}
}

void mostrarAyuda() {
	printf ("Estas ordenes de consola se encuentran definidas internamente.\n\n");
	printf ("-c ordenMaximo \t\tComprime usando hasta 'ordenMaximo'.\n");
	printf ("-d\t\t\tDescomprimir.\n");
	printf ("-f nombreArchivo\tSelecciona archivo de trabajo.\n");
	printf ("-e\t\t\tMuestra estadisticas de compresion.\n");
	printf ("-v\t\t\tMuestra todos lo contextos.\n");
	printf ("-vv nombreContexto\tMuestra el contexto indicado. Vacio para contexto 0.\n\n");

	printf ("-h\t\t\tMuestra la ayuda.\n");
}

bool numeroValido(char * numero){
	unsigned int pos =0;
	unsigned int longitud = strlen(numero);

	while (pos < longitud) {
		if (! (numero[pos]>= '0' && numero[pos] <= '9') ) return false;
		pos++;
	}
	return true;
}

int Interface::lanzarInterface(unsigned int cantidadArgumentos, char ** argumentos, TIPO_MANEJADOR tipo_manejador) {

	bool comprimir = false;
	bool descomprimir = false;
	bool verEstadisticas = false;
	bool verTodosContextos = false;
	bool ayuda = false;

	//Funciones primarias: Comprimir y Descomprimir. Si esta es correcta se ejecuta la/s secundaria/s
	bool primariaExitosa = false;

	map<int,char*> contextosVer;

	int orden = 0;
	char * nombreArchivo = NULL;
	char * opcion = NULL;
	unsigned int error = 0;

	unsigned int parametroActual = 1; //El parametro 0 tiene el path donde se esta ejecutando el programa

	while ( parametroActual < cantidadArgumentos && error == 0) {

		opcion = argumentos[parametroActual];

		if (strcmp(opcion,"-c") == 0 || strcmp(opcion,"-C") == 0) {

			//Comprimir
			comprimir = true;

			parametroActual++;
			if (!descomprimir) {
				//Indico el orden?
				if (parametroActual < cantidadArgumentos && numeroValido(argumentos[parametroActual])) {
					orden = atoi(argumentos[parametroActual]);
					if (orden < 0 || orden > 100 ) {
						error = ERROR_ORDEN;
					}
				} else {
					error = ERROR_ORDEN;
				}
			} else {
				error = ERROR_MULTIPLES_OPERACIONES;
			}

		} else if (strcmp(opcion,"-d") == 0 || strcmp(opcion,"-D") == 0) {

			//Descomprimir
			if (!comprimir) {
				descomprimir = true;
			} else {
				error= ERROR_MULTIPLES_OPERACIONES;
			}
		} else if (strcmp(opcion,"-e") == 0 || strcmp(opcion,"-E") == 0) {

			//Ver estadisticas
			verEstadisticas = true;

		} else if (strcmp(opcion,"-f") == 0 || strcmp(opcion,"-F") == 0) {
			//Archivo de destino
			parametroActual++;
			//Indico el archivo?
			if (parametroActual < cantidadArgumentos && !esOpcion(argumentos[parametroActual])) {
				nombreArchivo = new char [  strlen(argumentos[parametroActual])+1  ];
				strcpy(nombreArchivo, argumentos[parametroActual]);
			} else {
				error = ERROR_ARCHIVO;
			}

		} else if (strcmp(opcion,"-v") == 0 || strcmp(opcion,"-V") == 0) {
			//Mostrar todos los contextos
			verTodosContextos = true;

		} else if (strcmp(opcion,"-vv") == 0 || strcmp(opcion,"-VV") == 0) {
			//Mostrar contexto
			parametroActual++;
			//Si no especifico nada despues del -vv o es una opcion
			//se supone que se quiere ver el contexto ""
			if (parametroActual < cantidadArgumentos && !esOpcion(argumentos[parametroActual]) ) {
				contextosVer[contextosVer.size()] = argumentos[parametroActual];
			} else {
				char aux ='\0';
				contextosVer[contextosVer.size()] = &aux;
			}
		} else if (strcmp(opcion,"-h") == 0 || strcmp(opcion,"-H") == 0) {
			//Mostrar contexto
			ayuda = true;

		} else {
			//Parametro no encontrado
			error = ERROR_PARAMETRO_INEXISTENTE;
		}

		//Proceso el siguiente parametro
		parametroActual++;
	}

	if (error == 0) {
		if (nombreArchivo != NULL) {
			//Seleccion al menos una operacion?
			if (comprimir || descomprimir || verEstadisticas) {

				ManejadorContexto * manejador;

				//Se inicia el manejador
				if (tipo_manejador == ARBOLB) {
					manejador  = new ManejadorArbol(nombreArchivo);
				} else {
					manejador = new ManejadorHash (nombreArchivo);
				}

				Compresor * compresor = new Compresor(manejador);

				if (comprimir) {
					if (compresor->comprimir(orden, nombreArchivo) == Compresor::OPERACION_EXITOSA) {
						printf("Archivo comprimido exitosamente.\n");
						primariaExitosa = true;
					} else {
						printf("Error al comprimir. El archivo '%s' no existe.\n",nombreArchivo);
						primariaExitosa = false;
					}
				}

				if (descomprimir) {
					if ( esArchivoComprimido(nombreArchivo) || aceptaDescomprimirDistintaExtencion()  ) {
						if (compresor->descomprimir(nombreArchivo) == Compresor::OPERACION_EXITOSA) {
							printf("Archivo descomprimido exitosamente.\n");
							primariaExitosa = true;
						} else {
							printf("Error al descomprimir. El archivo '%s' no existe o esta corrupto.\n",nombreArchivo);
							primariaExitosa = false;
						}
					}
				}

				if (verEstadisticas) {
					//Ingreso un archivo comprimido?
					//Comprimio uno y desea ver las estadisticas?
					//Quiere ver las estadisticas de un archivo que no es .klow pero en realidad lo es?
					if ( esArchivoComprimido(nombreArchivo) || (comprimir && primariaExitosa) || (!comprimir && aceptaEstadisticasDistintaExtencion())  ) {
						if (!comprimir) {
							if (compresor->imprimir_estadisticas(nombreArchivo) != Compresor::OPERACION_EXITOSA) {
								printf("Error al intentar acceder a las estadisticas. El archivo '%s' no existe.\n",nombreArchivo);
							}
						} else {
							char * nombreAux = obtenerArchivoComprimido(nombreArchivo);
							if (compresor->imprimir_estadisticas(nombreAux) != Compresor::OPERACION_EXITOSA) {
								printf("Error al intentar acceder a las estadisticas. El archivo '%s' no existe.\n",nombreArchivo);
							}
							delete[](nombreAux);
						}
					}
				}

				if (primariaExitosa) {

					if (verTodosContextos) {
						printf("Contextos:\n");
						manejador->imprimirContextos(stdout);
					}

					if (contextosVer.size()) {
						printf("Contextos:\n");
						for (unsigned int i=0; i < contextosVer.size(); i++) {
							manejador->imprimirContextoParticular(stdout,contextosVer[i]);
						}
					}

				}
				delete(compresor);
				delete(manejador);
			}
		} else {
			if (!ayuda && cantidadArgumentos > 1) mostrarError(ERROR_ARCHIVO);
		}
	} else {
		mostrarError(error);
	}

	if (ayuda) {
		mostrarAyuda();
	}

	delete[](nombreArchivo);

	std::cout << std::endl << "Fin del programa" << std::endl;
	return 0;

}
